#include "util.h"
#include "symbol.h"
#include "absyn.h"

A_var A_SimpleVar(A_pos pos, S_symbol sym)
{
    A_var p = checked_malloc(sizeof(*p));
    p->kind = A_simpleVar;
    p->pos = pos;
    p->u.simple = sym;
    return p;
};

A_var A_FieldVar(A_pos pos, A_var main, A_var sub)
{
    A_var p = checked_malloc(sizeof(*p));
    p->kind = A_fieldVar;
    p->pos = pos;
    p->u.field.main = main;
    p->u.field.sub = sub;
    return p;
};

int searchSizeList(A_exp* sub, A_subList size, int depth)
{
    if (depth >= MAX_LINK_SIZE)
        return -1;

    if (size)
    {
        int result;
        sub[0] = size->data;
        result = searchSizeList(sub+1, size->next, depth+1);
        return result < 0? -1: result+1;
    }
    else
        return 0;
};

A_var A_SubscriptVar(A_pos pos, S_symbol name, A_subList size)
{
    A_var p = checked_malloc(sizeof(*p));
    p->kind = A_subscriptVar;
    p->pos = pos;
    p->u.subscript.name = name;
    p->u.subscript.size = searchSizeList(p->u.subscript.sub, size, 0);
    return p;
};

A_exp A_VarExp(A_pos pos, A_var v)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_varExp;
    p->pos = pos;
    p->u.var = v;
    return p;
};

A_exp A_IntExp(A_pos pos, int i)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_intExp;
    p->pos = pos;
    p->u.intt = i;
    return p;
};

A_exp A_StringExp(A_pos pos, string s)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_stringExp;
    p->pos = pos;
    p->u.stringg = s;
    return p;
};

A_exp A_CallExp(A_pos pos, S_symbol func, A_expList args)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_callExp;
    p->pos = pos;
    p->u.call.func = func;
    p->u.call.args = args;
    return p;
};
A_exp A_OpExp(A_pos pos, A_oper oper, A_exp left, A_exp right)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_opExp;
    p->pos = pos;
    p->u.op.oper = oper;
    p->u.op.left = left;
    p->u.op.right = right;
    return p;
};

A_exp A_AssignExp(A_pos pos, A_var var, A_exp exp)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_assignExp;
    p->pos = pos;
    p->u.assign.var = var;
    p->u.assign.exp = exp;
    return p;
};

A_exp A_SeqExp(A_pos pos, A_expList list)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_seqExp;
    p->pos = pos;
    p->u.seq = list;
    return p;
};

A_exp A_IfExp(A_pos pos, A_exp test, A_exp then, A_exp elsee)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_ifExp;
    p->pos = pos;
    p->u.iff.test = test;
    p->u.iff.then = then;
    p->u.iff.elsee = elsee;
    return p;
};

A_exp A_WhileExp(A_pos pos, A_exp test, A_exp body)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_whileExp;
    p->pos = pos;
    p->u.whilee.test = test;
    p->u.whilee.body = body;
    return p;
};

A_exp A_ForExp(A_pos pos, A_exp lo, A_exp test, A_exp hi, A_exp body,
    bool escape)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_forExp;
    p->pos = pos;
    p->u.forr.test = test;
    p->u.forr.lo = lo;
    p->u.forr.hi = hi;
    p->u.forr.body = body;
    p->u.forr.escape = FALSE;
    return p;
}
A_exp A_DecExp(A_pos pos, A_dec dec)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_decExp;
    p->pos = pos;
    p->u.dec = dec;
    return p;
};

A_exp A_AsmExp(A_pos pos, A_asmList asmm)
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_asmExp;
    p->u.asmm = asmm;
    return p;
}

A_exp A_BreakExp()
{
    A_exp p = checked_malloc(sizeof(*p));
    p->kind = A_breakExp;
    return p;
}

A_dec A_VarDec(A_pos pos, S_symbol var, S_symbol typ, A_exp init)
{
    A_dec p = checked_malloc(sizeof(*p));
    p->kind = A_varDec;
    p->pos = pos;
    p->u.var.var = var;
    p->u.var.typ = typ;
    p->u.var.init = init;
    p->u.var.escape = TRUE;
    return p;
};

A_field A_Field(A_pos pos, S_symbol name, S_symbol typ, bool escape)
{
    A_field p = checked_malloc(sizeof(*p));
    p->pos = pos;
    p->name = name;
    p->typ = typ;
    p->escape = escape;
    return p;
};

A_fieldList A_FieldList( A_field data, A_fieldList next)
{
    A_fieldList p = checked_malloc(sizeof(*p));
    p->data = data;
    p->next = next;
    return p;
};
A_expList A_ExpList(A_exp data, A_expList next)
{
    A_expList p = checked_malloc(sizeof(*p));
    p->data = data;
    p->next = next;
    return p;
};

A_dec A_TypeDec(A_pos pos, A_ty ty)
{
    A_dec p = checked_malloc(sizeof(*p));
    p->kind = A_typeDec;
    p->pos = pos;
    p->u.ty = ty;
    return p;
}

A_ty A_NameTy(A_pos pos, S_symbol name, S_symbol ty)
{
    A_ty p = checked_malloc(sizeof(*p));
    p->kind = A_nameTy;
    p->pos = pos;
    p->u.name.name = name;
    p->u.name.ty = ty;
    return p;
}

A_ty A_RecordTy(A_pos pos, S_symbol name, A_fieldList record)
{
    A_ty p = checked_malloc(sizeof(*p));
    p->kind = A_recordTy;
    p->pos = pos;
    p->u.record.name = name;
    p->u.record.record = record;
    return p;
}

// array is to be done
A_ty A_ArrayTy(A_pos pos, S_symbol name, S_symbol type, A_subList sub)
{
    int dim = 0;
    A_ty p = checked_malloc(sizeof(*p));
    p->kind = A_arrayTy;
    p->pos = pos;
    p->u.array.name = name;
    p->u.array.type = type;
    p->u.array.size = sub;
    while (sub)
    {
        dim ++;
        sub = sub->next;
    };
    p->u.array.dim = dim;
    return p;
}

A_dec A_FunDec(A_pos pos, S_symbol name, A_fieldList params,
        S_symbol result, A_exp body)
{
    A_dec p = checked_malloc(sizeof(*p));
    p->pos = pos;
    p->kind = A_funDec;
    p->u.fun.name = name;
    p->u.fun.params = params;
    p->u.fun.result = result;
    p->u.fun.body = body;
    return p;
};

A_expField A_ExpField(S_symbol name, A_exp exp)
{
    A_expField p = checked_malloc(sizeof(*p));
    p->name = name;
    p->exp = exp;
    return p;
};

A_expFieldList A_ExpFieldList(A_expField data, A_expFieldList next)
{
    A_expFieldList p = checked_malloc(sizeof(*p));
    p->data = data;
    p->next = next;
    return p;
};

A_asmList A_AsmList( string code, A_asmList next)
{
    A_asmList p = checked_malloc(sizeof(*p));
    p->code = code;
    p->next = next;
    return p;
};

A_subList A_SubList(A_exp data, A_subList next)
{
    A_subList p = checked_malloc(sizeof(*p));
    p->data = data;
    p->next = next;
    return p;
};

